//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2020-11-13     ZhangYihua   first version
//
// Description  : 
//################################################################################

module sync_sss #(  // sync same-source-stream data
parameter           DATA_BW                 = 12
) ( 
input                                       rst_src_n,
input                                       clk_src,
input                                       cke_src,

input               [DATA_BW-1:0]           src_dat,

input                                       rst_dst_n,
input                                       clk_dst,
input                                       cke_dst,

output  reg         [DATA_BW-1:0]           dst_dat
);

//################################################################################
// define local varialbe and localparam
//################################################################################
reg                 [3-1:0]                 src_adr;
reg                                         src_tog;
reg                 [6*DATA_BW-1:0]         dat_ary;
wire                                        s2d_tog;
reg                                         s2d_tog_1d;
wire                                        s2d_tog_chg;
wire                                        dst_stop;
reg                 [3-1:0]                 dst_adr;
reg                                         dst_en;
wire                [DATA_BW-1:0]           dst_dat_s;

//################################################################################
// main
//################################################################################

always@(posedge clk_src or negedge rst_src_n) begin
    if (rst_src_n==1'b0) begin
        src_adr <=`U_DLY 3'd0;
        src_tog <=`U_DLY 1'b0;
    end else if (cke_src==1'b1) begin
        if (src_adr>=3'd5) begin
            src_adr <=`U_DLY 3'd0;
            src_tog <=`U_DLY ~src_tog;
        end else
            src_adr <=`U_DLY src_adr + 1'd1;
    end else
        ;
end

always@(posedge clk_src or negedge rst_src_n) begin
    if (rst_src_n==1'b0) begin
        dat_ary <=`U_DLY {6*DATA_BW{1'b0}};
    end else if (cke_src==1'b1) begin
        dat_ary[src_adr*DATA_BW+:DATA_BW] <=`U_DLY src_dat;
    end else
        ;
end

sync_dff #(
        .SYNC_NUM                       (3                              ),
        .BW                             (1                              ),
        .INI                            (1'b0                           )
) u_s2d_tog ( 
        .rst_n                          (rst_dst_n                      ),
        .clk                            (clk_dst                        ),

        .d                              (src_tog                        ),
        .q                              (s2d_tog                        )
);

always@(posedge clk_dst or negedge rst_dst_n) begin
    if (rst_dst_n==1'b0) begin
        s2d_tog_1d <=`U_DLY 1'b0;
    end else if (cke_dst==1'b1) begin
        s2d_tog_1d <=`U_DLY s2d_tog;
    end else
        ;
end
assign s2d_tog_chg = s2d_tog_1d ^ s2d_tog;

assign dst_stop = ((s2d_tog_chg==1'b1) && (dst_adr!=3'd5) && (dst_adr!=3'd0)) ? 1'b1 : 1'b0;
always@(posedge clk_dst or negedge rst_dst_n) begin
    if (rst_dst_n==1'b0) begin
        dst_adr <=`U_DLY 3'd0;
    end else if (cke_dst==1'b1) begin
        if (dst_stop==1'b1)
            dst_adr <=`U_DLY dst_adr;
        else if (dst_adr>=3'd5)
            dst_adr <=`U_DLY 3'd0;
        else
            dst_adr <=`U_DLY dst_adr + 1'd1;
    end else
        ;
end

always@(posedge clk_dst or negedge rst_dst_n) begin
    if (rst_dst_n==1'b0) begin
        dst_en <=`U_DLY 1'b0;
    end else if (cke_dst==1'b1) begin
        dst_en <=`U_DLY dst_en | s2d_tog_chg;
    end else
        ;
end

n2o #(
        .PNUM                           (6                              ),	// source port number
        .DWID                           (DATA_BW                        ),	// data width of one port
        .SMODE                          ("BINARY"                       ) 	// sel is binary signal
) u_sel ( 
        .sel                            (dst_adr                        ),	// support one-hot and all-zero input when SMODE
        .np_dat                         (dat_ary                        ),
        .op_dat                         (dst_dat_s                      )
);

always@(posedge clk_dst or negedge rst_dst_n) begin
    if (rst_dst_n==1'b0) begin
        dst_dat <=`U_DLY {DATA_BW{1'b0}};
    end else if ((cke_dst==1'b1) && (dst_en==1'b1)) begin
        dst_dat <=`U_DLY dst_dat_s;
    end else
        ;
end

//################################################################################
// ASSERTION
//################################################################################

`ifdef CBB_ASSERT_ON
// synopsys translate_off


// synopsys translate_on
`endif

endmodule
